/**
 * grayrabbit Inc.
 * Copyright (c) 2011-2012 All Rights Reserved.
 */
package com.grayrabbit.slacker.config.provider;

import java.util.HashMap;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.grayrabbit.slacker.config.Configuration;
import com.grayrabbit.slacker.config.GenerateConfig;
import com.grayrabbit.slacker.config.Property;
import com.grayrabbit.slacker.factory.DatabaseProdiverFactory;

/**
 * XML配置信息处理类
 * 
 * @author liyd
 * @version $Id: XmlConfigParseProvider.java, v 0.1 2012-5-8 下午5:45:57 liyd Exp $
 */
public class XmlConfigParseProvider {

    /** 日志对象 */
    private final static Logger    LOG                     = Logger
                                                               .getLogger(XmlConfigParseProvider.class);

    /** 配置文件 */
    private String                 configFile              = "default-config.xml";

    /** 默认配置文件指定key名称 */
    private final static String    DEFAULT_CONFIG_FILE_KEY = "xml.config.file";

    /** 数据库标签 */
    private final static String    XML_DATABASE_LABLE      = "database";

    /** include 标签 */
    private final static String    XML_INCLUDE_LABLE       = "include";

    /** file属性名 */
    private final static String    XML_FILE_ATTR           = "file";

    /** xml表标签 */
    private final static String    XML_TABLE_LABLE         = "table";

    /** xml name属性 */
    private final static String    XML_NAME_ATTR           = "name";

    /** xml replace属性 */
    private final static String    XML_REPLACE_ATTR        = "replace";

    /** xml class属性 */
    private final static String    XML_CLASS_ATTR          = "class";

    /** xml value属性 */
    private final static String    XML_VALUE_ATTR          = "value";

    /** xml多出来的text标签 */
    private final static String    XML_TEXT_LABLE          = "#text";

    /** 多表之间分隔符 */
    private final static String    TABLE_SEPARATOR         = ",";

    /** doc 构建工厂 */
    private DocumentBuilderFactory docBuilderFactory       = null;

    /** doc builder */
    private DocumentBuilder        docBuilder              = null;

    /**
     * 初始化配置信息
     */
    public static void xmlConfigInit() {

        XmlConfigParseProvider xmlConfigProvider = new XmlConfigParseProvider();

        xmlConfigProvider.parseConfingFile();
    }

    /**
     * 获取需要解析的配置文件
     * 
     * @return
     */
    private void init() {

        //需要解析的文件
        String tmp = PropertiesProvider.getProperty(DEFAULT_CONFIG_FILE_KEY);
        if (tmp != null && !"".equals(tmp.trim())) {
            configFile = tmp;
        }

        try {
            //创建xml解析doc对象
            this.docBuilderFactory = DocumentBuilderFactory.newInstance();
            this.docBuilder = docBuilderFactory.newDocumentBuilder();

        } catch (ParserConfigurationException e) {
            LOG.error("创建xml构造对象失败", e);
        }
    }

    /**
     * 解析配置文件
     * 
     */
    public void parseConfingFile() {

        init();

        try {

            //创建xml解析doc对象
            Document defaultDoc = docBuilder.parse(this.getClass().getClassLoader()
                .getResourceAsStream(configFile));

            //解析数据库处理类配置
            NodeList dbList = defaultDoc.getElementsByTagName(XML_DATABASE_LABLE);

            //处理数据库配置
            parseDatabase(dbList);

            //解析任务，得到xml 任务集合标签
            NodeList includeList = defaultDoc.getElementsByTagName(XML_INCLUDE_LABLE);

            //解析include文件
            parseIncludeFile(includeList);

            //解析表配置
            NodeList tableList = defaultDoc.getElementsByTagName(XML_TABLE_LABLE);

            //处理表配置
            parseTable(tableList);

        } catch (Exception e) {
            LOG.error("配置文件解析失败", e);
        }

    }

    /**
     * 解析数据库配置
     * 
     * @param dbList
     */
    private void parseDatabase(NodeList dbList) {

        if (dbList == null || dbList.getLength() == 0) {
            LOG.info("没有数据库配置");
            return;
        }

        try {
            for (int i = 0; i < dbList.getLength(); i++) {

                Node dbNode = dbList.item(i);

                NamedNodeMap dbNodeMap = dbNode.getAttributes();

                String name = dbNodeMap.getNamedItem(XML_NAME_ATTR).getNodeValue();

                String clazz = dbNodeMap.getNamedItem(XML_CLASS_ATTR).getNodeValue();

                Object obj = Class.forName(clazz).newInstance();

                DatabaseProdiverFactory.addProviderClass(name, obj);

            }
        } catch (Exception e) {
            LOG.error("解析配置的数据库处理类失败", e);
        }

    }

    /**
     * 解析include的xml
     * 
     * @param includeList
     */
    private void parseIncludeFile(NodeList includeList) throws Exception {

        if (includeList == null || includeList.getLength() == 0) {
            LOG.info("include 文件列表为空");
            return;
        }

        //处理include文件
        for (int i = 0; i < includeList.getLength(); i++) {

            Node includeNode = includeList.item(i);

            NamedNodeMap includeNodeMap = includeNode.getAttributes();

            String includeFile = includeNodeMap.getNamedItem(XML_FILE_ATTR).getNodeValue();

            LOG.info("加载[" + includeFile + "],开始解析");

            //创建xml解析doc对象
            Document doc = docBuilder.parse(this.getClass().getClassLoader()
                .getResourceAsStream(includeFile));

            //解析表配置信息任务
            NodeList tableList = doc.getElementsByTagName(XML_TABLE_LABLE);

            //处理表配置信息任务
            parseTable(tableList);

            LOG.info("文件[" + includeFile + "],解析完毕");

        }

    }

    /**
     * 解析表配置
     * 
     * @param tableList
     */
    private void parseTable(NodeList tableList) {

        if (tableList == null || tableList.getLength() == 0) {
            return;
        }

        //处理表配置信息
        for (int i = 0; i < tableList.getLength(); i++) {

            //表信息
            Node tableNode = tableList.item(i);

            NamedNodeMap tableNodeMap = tableNode.getAttributes();

            //表名称
            String tableNamesStr = tableNodeMap.getNamedItem(XML_NAME_ATTR).getNodeValue();

            if (tableNamesStr == null || "".equals(tableNamesStr)) {
                LOG.info("没有指定表名");
                return;
            }

            String[] tableNames = tableNamesStr.split(TABLE_SEPARATOR);

            for (String tableName : tableNames) {

                //替换标识
                String replace = tableNodeMap.getNamedItem(XML_REPLACE_ATTR).getNodeValue();

                //表的生成任务列表
                NodeList generateList = tableNode.getChildNodes();

                //处理表的生成任务列表
                parseGenerate(generateList, tableName, Boolean.valueOf(replace));

            }

        }

    }

    /**
     * 解析表的任务配置 并添加任务
     * 
     * @param generateList
     * @param tableName
     * @param replace
     */
    private void parseGenerate(NodeList generateList, String tableName, Boolean replace) {

        if (generateList == null || generateList.getLength() == 0) {
            LOG.info("表的生成任务列表为空");
            return;
        }

        //处理任务配置信息
        for (int i = 0; i < generateList.getLength(); i++) {

            //任务
            Node generateNode = generateList.item(i);

            if (XML_TEXT_LABLE.equals(generateNode.getNodeName())) {
                continue;
            }

            //任务信息对象
            GenerateConfig generateConfig = new GenerateConfig();
            generateConfig.setTableName(tableName);
            generateConfig.setReplace(replace);

            NamedNodeMap generateNodeMap = generateNode.getAttributes();

            //任务名称
            String generateName = generateNodeMap.getNamedItem(XML_NAME_ATTR).getNodeValue();

            //处理类名称
            String className = generateNodeMap.getNamedItem(XML_CLASS_ATTR).getNodeValue();

            generateConfig.setGenerateName(generateName);
            generateConfig.setClazz(className);

            //属性信息
            NodeList propertyList = generateNode.getChildNodes();

            //处理属性
            Map<String, Property> propertyMap = parseProperties(propertyList);

            generateConfig.setProperties(propertyMap);

            //添加任务，以表名加各分级任务名为key，也就是说一个表有多个任务
            Configuration.offerGenerateConfig(generateConfig);

            LOG.info("已添加生成队列任务：[table=" + generateConfig.getTableName() + ",generate="
                     + generateConfig.getGenerateName() + "]");
        }

    }

    /**
     * 解析属性标签信息
     * 
     * @param propertyList
     */
    private Map<String, Property> parseProperties(NodeList propertyList) {

        if (propertyList == null || propertyList.getLength() == 0) {
            return null;
        }

        Map<String, Property> propertyMap = new HashMap<String, Property>();

        //处理属性配置信息
        for (int i = 0; i < propertyList.getLength(); i++) {

            Node propertyNode = propertyList.item(i);

            if (XML_TEXT_LABLE.equals(propertyNode.getNodeName())) {
                continue;
            }

            //属性对象
            Property property = new Property();

            NamedNodeMap propertyNodeMap = propertyNode.getAttributes();

            //属性名称
            String propertyName = propertyNodeMap.getNamedItem(XML_NAME_ATTR).getNodeValue();

            //属性值
            String propertyValue = propertyNodeMap.getNamedItem(XML_VALUE_ATTR).getNodeValue();

            property.setName(propertyName);
            property.setValue(propertyValue);

            if (propertyNode.hasChildNodes()) {

                //递归读取子属性信息
                property.setChildProperties(parseProperties(propertyNode.getChildNodes()));

            }

            propertyMap.put(propertyName, property);
        }

        return propertyMap;
    }

}
